use super::{common, config, git, page_template_helper::PageTemplateHelper};
use crate::errors::{MyError, MyResult};
use crate::models::{
    CliConfig, ComponentStagingItems, Components, ComposeAreaItem, PageStagingItem,
    PageStagingItems, Pages, ProjectBase,
};

type PageStagingItemHandle = Box<dyn Fn(&PageStagingItem) -> MyResult<()>>;
pub fn init_project_base(project_base: &ProjectBase) -> MyResult<()> {
    println!("init project base");
    git::clone(
        &project_base.git,
        &project_base.tag,
        Some(config::PROJECT_BASE_PATH),
    )?;
    Ok(())
}
pub async fn init_pages(pages: &Pages) -> MyResult<()> {
    println!("init pages");
    git::clone(
        &pages.git,
        &pages.tag,
        Some(&common::path_join(
            config::PROJECT_BASE_PATH,
            &git::get_default_git_project_name(&pages.git)?,
        )?),
    )?;
    git::append_ignore(
        config::PROJECT_BASE_PATH,
        &git::get_default_git_project_name(&pages.git)?,
    )?;
    Ok(())
}
pub async fn init_components(components: &Components) -> MyResult<()> {
    println!("init components");
    git::clone(
        &components.git,
        &components.tag,
        Some(&common::path_join(
            config::PROJECT_BASE_PATH,
            &git::get_default_git_project_name(&components.git)?,
        )?),
    )?;
    git::append_ignore(
        config::PROJECT_BASE_PATH,
        &git::get_default_git_project_name(&components.git)?,
    )?;
    Ok(())
}

pub fn config_templates(config: &CliConfig) -> MyResult<()> {
    let page_staging_items: &PageStagingItems = &config.pages.clone().try_into()?;
    let component_staging_items: &ComponentStagingItems = &config.components.clone().try_into()?;

    if let Some(result) = config
        .compose_areas
        .items
        .iter()
        .map(|item| {
            PageTemplateHelper::config_template(item, page_staging_items, component_staging_items)
        })
        .find(|x| x.is_err())
    {
        return Err(MyError::Msg(format!("{:?}", result)));
    }
    Ok(())
}
pub fn config_components(config: &CliConfig) -> MyResult<()> {
    let page_staging_items: &PageStagingItems = &config.pages.clone().try_into()?;

    let handle_page_staging_item: PageStagingItemHandle =
        Box::new(|page_staging_item: &PageStagingItem| {
            common::write_project_file(
                &page_staging_item.mixins_components_path,
                &PageTemplateHelper::build_components_mixins(&common::load_project_file(
                    &page_staging_item.mixins_components_staging_path,
                )?)?,
            )
        });
    if let Some(result) = page_staging_items
        .items
        .iter()
        .map(handle_page_staging_item)
        .find(|x| x.is_err())
    {
        return Err(MyError::Msg(format!("{:?}", result)));
    }

    let handle_events_staging: PageStagingItemHandle =
        Box::new(|page_staging_item: &PageStagingItem| {
            common::write_project_file(
                &page_staging_item.module_methods_path,
                &PageTemplateHelper::build_events_mixins(&common::load_project_file(
                    &page_staging_item.mixins_methods_staging_path,
                )?)?,
            )
        });

    if let Some(result) = page_staging_items
        .items
        .iter()
        .map(handle_events_staging)
        .find(|x| x.is_err())
    {
        return Err(MyError::Msg(format!("{:?}", result)));
    }

    if let Some(result) = page_staging_items
        .items
        .iter()
        .map(PageTemplateHelper::remove_staging)
        .find(|x| x.is_err())
    {
        return Err(MyError::Msg(format!("{:?}", result)));
    }

    Ok(())
}
pub fn init_mixin_folder() -> MyResult<()> {
    common::init_project_folder(config::MIXINS_FOLDER_NAME)
}
pub fn init_module_folders(page_staging_items: &PageStagingItems) -> MyResult<()> {
    for item in &page_staging_items.items {
        common::init_project_folder(&item.mixins_folder_path)?;
    }
    Ok(())
}
